from rest_framework import permissions
from functools import wraps
from django.core.cache import cache
from django.conf import settings
from rest_framework.exceptions import PermissionDenied
from rest_framework.permissions import DjangoModelPermissions

class HasModelPermission(permissions.BasePermission):
    """
    自定义权限类，检查用户是否有指定模型的权限
    """
    def has_permission(self, request, view):
        # 超级用户拥有所有权限
        if request.user.is_superuser:
            return True
            
        # 获取当前视图对应的模型名称
        model_name = view.get_queryset().model._meta.model_name
        app_label = view.get_queryset().model._meta.app_label
        
        # 根据请求方法确定需要的权限类型
        if request.method in permissions.SAFE_METHODS:  # GET, HEAD, OPTIONS
            perm = f'{app_label}.view_{model_name}'
        elif request.method == 'POST':
            perm = f'{app_label}.add_{model_name}'
        elif request.method in ['PUT', 'PATCH']:
            perm = f'{app_label}.change_{model_name}'
        elif request.method == 'DELETE':
            perm = f'{app_label}.delete_{model_name}'
        else:
            return False

        # 使用缓存检查权限
        return self.has_cached_permission(request.user, perm)

    def has_object_permission(self, request, view, obj):
        return self.has_permission(request, view)

    def has_cached_permission(self, user, perm):
        """
        使用缓存检查用户权限
        """
        if user.is_superuser:
            return True

        # 生成缓存键
        cache_key = f'user_perm_{user.id}_{perm}'
        cached_result = cache.get(cache_key)

        if cached_result is not None:
            return cached_result

        # 检查用户是否有权限（包括通过组获得的权限）
        has_perm = user.has_perm(perm)
        
        # 缓存结果
        cache.set(cache_key, has_perm, timeout=settings.PERMISSION_CACHE_TIMEOUT)
        
        return has_perm

class StaffModelPermissions(DjangoModelPermissions):
    """
    Custom permissions class that gives full permissions to staff users.
    Staff users bypass all model permission checks.
    Non-staff users still need explicit model permissions.
    """
    
    def has_permission(self, request, view):
        # If user is staff, grant all permissions
        if request.user and request.user.is_staff:
            return True
        # Otherwise, fall back to default DjangoModelPermissions behavior
        return super().has_permission(request, view)

def require_permissions(*perms):
    """
    自定义权限装饰器，用于视图函数
    使用方法：
    @require_permissions('app_label.permission_codename', 'app_label.other_permission')
    def your_view_function(request):
        ...
    """
    def decorator(view_func):
        @wraps(view_func)
        def wrapped_view(view_instance, request, *args, **kwargs):
            user = request.user

            # 检查是否登录
            if not user.is_authenticated:
                raise PermissionDenied("Authentication required")

            # 超级用户直接通过
            if user.is_superuser:
                return view_func(view_instance, request, *args, **kwargs)

            # 检查所有必需权限
            for perm in perms:
                cache_key = f'user_perm_{user.id}_{perm}'
                has_perm = cache.get(cache_key)

                if has_perm is None:
                    has_perm = user.has_perm(perm)
                    cache.set(cache_key, has_perm, timeout=3600)

                if not has_perm:
                    raise PermissionDenied(f"Missing required permission: {perm}")

            return view_func(view_instance, request, *args, **kwargs)
        return wrapped_view
    return decorator

def clear_permission_cache(user_id):
    """
    清除用户的权限缓存
    在用户权限变更时调用
    """
    pattern = f'user_perm_{user_id}_*'
    if hasattr(cache, 'delete_pattern'):
        cache.delete_pattern(pattern)
    else:
        # 如果缓存后端不支持模式删除，可以记录用户的权限缓存键
        # 这里可以根据实际情况实现
        pass

def get_or_create_staff_group():
    """
    获取或创建员工组
    """
    from django.contrib.auth.models import Group
    
    # 获取或创建员工组
    staff_group, created = Group.objects.get_or_create(name='员工组')
    
    return staff_group

def set_staff_default_permissions(user):
    """
    为员工设置默认权限组
    """
    if not user.is_staff:
        return
    
    # 获取员工组
    staff_group = get_or_create_staff_group()
    
    # 将用户添加到员工组
    if staff_group not in user.groups.all():
        user.groups.add(staff_group)
    
    # 清除权限缓存
    clear_permission_cache(user.id)

def register_custom_permissions(model, permissions):
    """
    为模型注册自定义权限
    model: 模型类
    permissions: 权限列表，格式为 [(codename, name), ...]
    """
    try:
        from django.contrib.auth.models import Permission
        from django.contrib.contenttypes.models import ContentType
        
        content_type = ContentType.objects.get_for_model(model)
        
        for codename, name in permissions:
            Permission.objects.get_or_create(
                codename=codename,
                name=name,
                content_type=content_type,
            )
    except Exception:
        # 忽略数据库错误，允许在迁移前注册权限
        pass

def generate_action_permission(model_name, action_name, description=None):
    """
    生成 action 对应的权限代码和描述
    """
    codename = f"{action_name}_{model_name}"
    name = description or f"Can {action_name} {model_name}"
    return codename, name
